import { TextRenderer, GameObject, getGameObjectById, Behaviour, GameEngineCore, HitTestScript, registerScript, Transform, isEditorMode } from "./gameengine";
import { rootData } from "./data";
import { TileMapRenderer } from "./tilemap";
import { uiPrefabData } from "./mapData";
import { astar } from "./astar";
import { CommandBase, CommandPool } from "./command";
import { ItemLayerBehaviour, PickItemCommand } from "./item";
import { user } from "./user";
import { NpcBehaviour } from "./npc";

// https://www.w3cschool.cn/html5/q2ybmfle.html

//平移运动代码
export class MoveScript extends Behaviour {
    
    speedX: number = 0;
    speedY: number = 0;

    onStart() {

    }

    onUpdate() {
        const transform = this.displayObject.getScript(Transform);
        transform.x += this.speedX;
        transform.y += this.speedY;
    }

    onClick() {

    }

    parseData(data: any) {
        this.speedX = data.speedX;
    }
}

export class MainDisplayObjectScript extends Behaviour {

    parseData(data: any) {

    }
    onStart() {
        const hitTest = this.displayObject.getScript(HitTestScript);
        hitTest.onClick = () => {
            const moveScript = this.displayObject.getScript(MoveScript);
            //moveScript.speedX = 0;
        }
    }
    onUpdate() {
    }
}

//人物运动
export class WalkableBehaviour extends Behaviour {

    private path: { x: number, y: number }[] = [];

    private speedY: number = 0;
    private speedX: number = 0;

    private pathIndex = 0;

    onFinished: Function;

    onStart() {
    }

    setStartPosition(startX: number, startY: number) {
        const transform = this.displayObject.getScript(Transform);
        transform.x = startX;
        transform.y = startY;
    }

    goto(path: { x: number, y: number }[]) {
        this.path = path;
        this.pathIndex = 0;

    }

    onUpdate() {
        if (!this.path[this.pathIndex]) {
            return;
        }
        const transform = this.displayObject.getScript(Transform);

        const targetX = this.path[this.pathIndex].x;
        const targetY = this.path[this.pathIndex].y;
        if (transform.y === targetY) {
            this.speedY = 0;
        }
        else if (transform.y < targetY) {
            this.speedY = 1;
        }
        else {
            this.speedY = -1;
        }
        if (transform.x === targetX) {
            this.speedX = 0;
        }
        else if (transform.x < targetX) {
            this.speedX = 1;
        }
        else {
            this.speedX = -1;
        }


        const arrivedSingleTarget = transform.x === targetX && transform.y === targetY;
        if (arrivedSingleTarget) {
            this.pathIndex++;
            if (this.pathIndex >= this.path.length) {
                if (this.onFinished) {
                    this.onFinished();
                }
            }
        }

        transform.x += this.speedX;
        transform.y += this.speedY;
    }

}

//寻路命令
class WalkCommand extends CommandBase {

    private walkable: WalkableBehaviour;
    private tileX: number;
    private tileY: number;

    constructor(walkable: WalkableBehaviour, tileX: number, tileY: number) {
        super();
        this.walkable = walkable;
        this.tileX = tileX;
        this.tileY = tileY;
    }

    execute() {

        const findpath = new astar.FindPath();
        const tilemap = getGameObjectById("tilemap");
        const grid = tilemap.getScript(TileMapRenderer).grid;
        findpath.setHeurisitic(findpath.euclidian);
        const transform = this.walkable.displayObject.getScript(Transform);
        const startX = Math.floor(transform.x / 64);
        const startY = Math.floor(transform.y / 64);

        const paths = findpath.findPath(grid, startX, startY, this.tileX, this.tileY);
        const path = paths.map(node => {
            return { x: node.x * 64, y: node.y * 64 }
        });
        path.shift();
        this.walkable.onFinished = () => {
            this.onFinished();
        }
        this.walkable.goto(path);
    }

    cancel(): void {
        console.log('取消移动')
    }
}

//与NPC对话的命名
class TalkCommand extends CommandBase {
    private ui: GameObject;
    execute(): void {
        const ui = core.createPrefab(uiPrefabData);
        const uiRoot = getGameObjectById("UIRoot");
        uiRoot.getScript(HitTestScript).onClick = () => {
            uiRoot.removeChild(ui);
            this.onFinished();
        }
        uiRoot.addChild(ui);
        this.ui = ui;
    }

    cancel() {
        const uiRoot = getGameObjectById("UIRoot");
        uiRoot.removeChild(this.ui);
    }

}

//游戏角色行为
export class MainRoleBehaviour extends Behaviour {

    private commandPool = new CommandPool();


    private goto(tileX: number, tileY: number) {
        const walkable = this.displayObject.getScript(WalkableBehaviour)
        const walkCommand1 = new WalkCommand(walkable, tileX, tileY);
        //将寻路命令推入队列
        this.commandPool.push(walkCommand1);

        const itemLayer = getGameObjectById('itemLayer');
        const itemLayerBehaviour = itemLayer.getScript(ItemLayerBehaviour);
        const item = itemLayerBehaviour.getItemByTileXY(tileX, tileY);
        if (item) { //当走到物品上时执行捡拾命令
            const pickItemCommand = new PickItemCommand(item);
            this.commandPool.push(pickItemCommand);
        }

        // const npcLayer = getGameObjectById('npcLayer');
        // const npcLayerBehaviour = npcLayer.getScript(NPCLayerBehaviour);
        // const npc = npcLayerBehaviour.getNPCByTileXY(tileX, tileY + 1);
        // if (npc) { //当走到NPC正面才触发对话命令
        //     const talkNPCCommand = new TalkNPCCommand(npc);
        //     this.commandPool.push(talkNPCCommand);
        // }
        else {
            const talkCommand = new TalkCommand();
            this.commandPool.push(talkCommand);
        }

        this.commandPool.seriesExecuteAllCommand(); 

    }

    onStart() {
        const tilemap = getGameObjectById("tilemap");
        const hitTest = tilemap.getScript(HitTestScript);
        hitTest.onClick = (localX, localY) => {
            const tileX = Math.floor(localX / 64);
            const tileY = Math.floor(localY / 64);
            this.goto(tileX, tileY);
        }

    }
    onUpdate() {

    }

}

export class TopUIBehaviour extends Behaviour {
    onStart() {

    }

    onUpdate() {
        const score = this.displayObject.getScript(TextRenderer);
        score.fontSize = user.fontSize;
        score.text = user.gold.toString();
    }

}


//registerScript(MoveScript);
//registerScript(MainDisplayObjectScript);
registerScript(TileMapRenderer);
registerScript(MainRoleBehaviour);
registerScript(WalkableBehaviour);
//registerScript(EnemyBehaviour);
registerScript(ItemLayerBehaviour);
registerScript(TopUIBehaviour);
//registerScript(NPCLayerBehaviour);
registerScript(NpcBehaviour);

export const core = new GameEngineCore();

core.loadImage("assets/0.png");
core.loadImage("assets/1.png");
core.loadImage("assets/MainRole.png");
core.loadImage("assets/npc.png");
core.loadImage("assets/enemy.png");
core.loadImage("assets/notice.png");
core.loadImage("assets/money.png");
core.loadImage("assets/sword.png");

// core.createScene(mapData);
core.start();

const xhr = new XMLHttpRequest();
xhr.onload = () => {
    const json = JSON.parse(xhr.responseText);
    console.log('load data');
    console.log(json);
    core.createScene(json);
    core.start();
}
if (!isEditorMode()){
    core.loadScene('game.scene.json')
}

//考虑如何切换场景 像unity那样切换我想要编辑的那个场景
//把加载场景封装到游戏场景里面
//这样在其他文档中调用的时候就可以尝试使用不同场景的切换